#!/usr/bin/env node
/*
 *   Copyright (C) 2017 Igor Konovalov
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

const p = require('path');
const colors = require('colors');

const commandLineArgs = require('command-line-args');
const getUsage = require('command-line-usage');

const ARROW = '\u2192';
const INFINITY = '\u221E';

// command line
const defaultConfigLocation = p.join(p.dirname(__filename), '../config/app.yml');

const optionDefinitions = [
    { name: 'mode',   type: String, defaultValue: 'ectag', defaultOption: true, alias: 'm' },
    { name: 'offset', type: Number, defaultValue: 50, alias: 's'},
    { name: 'scan-to', type: Number, defaultValue: Infinity, alias: 'e'},
    { name: 'config', type: String, defaultValue: defaultConfigLocation, alias: 'c'},
    { name: 'fail-fast', type: Boolean, defaultValue: false },
    { name: 'help', alias: 'h', type: Boolean }
];

const options = commandLineArgs(optionDefinitions);

if (options.help) {
    console.log(getUsage([
        {
            header: 'File force harvester (IPFS-Ethereum)',
            content: "Listening FileForce's  IPFS activity in Ethereum"
        },
        {
            header: 'Options',
            optionList: [
                {
                    name: 'mode',
                    typeLabel: '[underline]{file|ectag|ecdtag}',
                    description: 'Switch to specified ethereum contract events. [italic]{Default options.}'
                },
                {
                    name: 'offset',
                    typeLabel: '[underline]{block}',
                    description: 'Listen from specified block'
                },
                {
                    name: 'scan-to',
                    typeLabel: '[underline]{block}',
                    description: 'Listen to specified block. Default is infinity.'
                },
                {
                    name: 'config',
                    typeLabel: '[underline]{config-path}',
                    description: 'Configuration file location.'
                },
                {
                    name: 'fail-fast',
                    description: 'Crashes process on error'
                }
            ]
        }
    ]));
    process.exit(0);
}

// fileforce, ethereum and redundant

const FileForceEth = require('../lib/libfileforce-eth');

const Redundant = require('../lib/libredundant');

// event map and  handlers

function pull(hashBn, event) {
    let ipfsHash = FileForceEth.bnToMultihash58(hashBn);
    redundant.pull(ipfsHash, (error, done) => {
        console.log(`${ipfsHash} on ${event.blockNumber} block ${error ? error : done}`);

        // let it down if fail-fast option is enabled
        if (error && options['fail-fast']) {
            throw error
        }
    })
}

const modeToEvent = {
    file: {
        event: FileForceEth.eventType.NewFileAppeared,
        handler: (event) => {
            pull(event.args.ipfs, event);
        }
    },
    ectag:  {
        event: FileForceEth.eventType.EcTagRegistered,
        handler: (event) => {
            pull(event.args.ipfs, event);
        }
    },
    ecdtag: {
        event: FileForceEth.eventType.EcTagDelegated,
        handler: (event) => {
            pull(event.args.ipfsOrigin, event);
            pull(event.args.ipfsNew, event);
        }
    }
};

console.log(`File Force Harvester (FFH). Mode: ${options.mode}`);

const config = require('yaml-config').readConfig(options.config);

const redundant = new Redundant(config);

const fileForce = new FileForceEth(config);

const lastBlock = fileForce.ethereum.lastBlock.number;

const eventFilter = {};

const blockFilter = {
    fromBlock: lastBlock - options.offset,
    toBlock: options['scan-to'] == Infinity ? 'latest' : options['scan-to']
};

console.log(`Block range: ${blockFilter.fromBlock} ${ARROW} ${INFINITY}`.blue);

const mode = modeToEvent[options.mode];

var startHarvesting = (eventType) => {
    fileForce.watchEvents(
        eventType,
        eventFilter,
        blockFilter,
        (error, event) => {
            if (!error) {
                mode.handler(event)
            }
        });
};

startHarvesting(mode.event);
